# 安装：pip3 install pyserial   //python3
import serial
import serial.tools.list_ports
import time
import threading

class BinConvert:
    _v=[0]*256
    m_readInx=0
    m_writeInx=0
    @staticmethod
    def arrayCopy(sourceArray, sourceIndex, destinationArray, destinationIndex, length):
        for i in range(0, length):
            destinationArray[i+destinationIndex]=sourceArray[i+sourceIndex]

    @staticmethod
    def buildByBuf(buf):
        binConvert=  BinConvert()
        binConvert._v=buf;
        binConvert.m_readInx=0;
        binConvert.m_writeInx=len(buf);
        return binConvert;

    def reset(self):
        self.m_readInx=0
        self.m_writeInx=0

    def getNextStr(self):
        if(self.m_readInx> len(self._v) -16):
            return "";
        s = BinConvert.bytes2Str(self._v, self.m_readInx, 16);
        self.m_readInx= self.m_readInx+16;
        return s;

    def  getNextInt(self,l):
        if(self.m_readInx > len(self._v)-l):
            return 0;
        retInt= BinConvert.bytes2Int(self._v,self.m_readInx,l);
        self.m_readInx= self.m_readInx+l;
        return retInt;

    def  appendStr(self,str):
        strBytes=BinConvert.str2bytes(str);
        BinConvert.arrayCopy(strBytes, 0, self._v,   self.m_writeInx, len(strBytes));
        self.m_writeInx= self.m_writeInx+len(strBytes);

    def appendInt(self,intVal,intLen):
        int2Bytes=BinConvert.int2Bytes(intVal,intLen);
        BinConvert.arrayCopy(int2Bytes, 0, self._v,   self.m_writeInx, len(int2Bytes));
        self.m_writeInx= self.m_writeInx+intLen;


    def appendBuf(self,buf):
        BinConvert.arrayCopy(buf, 0, self._v, self.m_writeInx, len(buf));
        self.m_writeInx= self.m_writeInx+ len(buf);

    def toBuf(self):
        return self._v[:self.m_writeInx]

    @staticmethod
    def bytes2Int(bs,start,length):
        bytesLen = length;
        if bytesLen==0:
            return bs[start+0];
        elif bytesLen==1:
            return bs[start+0];
        elif bytesLen==2:
            return bs[start+0]+bs[start+0+1]*256;
        elif bytesLen==4:
            return bs[start+0]+ bs[start+0+1]*256+bs[start+0+2]*65536+bs[start+0+3]*16777216
        return 0

    @staticmethod
    def bytes2Str(bs,start=0,length=0):
        if length==0:
            length=len(bs)
        arrDis=[0]*length;
        for i in range(length):
            if bs[start+i] == 0:
                break
            arrDis[i]=bs[start+i];

        result = ''.join(chr(code) for code in arrDis)
        return result

    @staticmethod
    def int2Bytes(v,length):
        bytesLen = length;
        if bytesLen==1:
            return [v & 0xff];
        elif bytesLen==2:
            return [v &0xff ,v>>8 &0xff]
        elif bytesLen==4:
            return [v &0xff, v>>8 &0xff,v>>16 &0xff, v>>24 &0xff ]
        return []

    @staticmethod
    def str2bytes(str):
        s = str
        b = s.encode('GBK')
        bytes= list(b)
        if len(bytes)<16:
            bytes += [0] * (16 - len(bytes))
        else:
            bytes=bytes[0:16]
        return bytes
    
    @staticmethod
    def text2bytes(str):
        s = str
        b = s.encode('GBK')
        bytes= list(b)
        return bytes

    @staticmethod
    def parseInt(s):
        try:
            if not isinstance(s, str):
                return s
            if s.startswith("0"):
                return int(s, 16)
            else:
                return int(s)
        except ValueError:
            try:
                return float(s)
            except ValueError:
                return None

    @staticmethod
    def isNumStr(s):
        try:
            if isinstance(s, str) and re.match(r'^[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?$', s):
                return True
            elif isinstance(s, str) and re.match(r'^[-+]?0[xX][0-9A-Fa-f]+$', s):
                return True
            else:
                return False
        except TypeError:
            return False

    @staticmethod
    def  arraySlice(bs, start):
        bytes =[0]*(len(bs)-start);
        BinConvert.arrayCopy(bs,start,bytes,0,len(bs) - start);
        return bytes;

    @staticmethod
    def arrayMoveLeft(dstBs, start):
        if(len(dstBs) <start):
            return;
        len=len(dstBs)-start;
        for i in range(0, len):
            dstBs[i]=dstBs[i+start];

    @staticmethod
    def zfill(string, width):
        if len(string) < width:
            return '0' * (width - len(string)) + string
        return string

    @staticmethod
    def bytes2HexStr(bytes, start=0, length=0):
        if(start==0):
            start=0;
        if(length==0):
            length=len(bytes);
        disv="";
        for i in range(0, length):
            disv=disv+ BinConvert.zfill(hex(bytes[start+i])[2:],2)+" ";
        return disv;

    @staticmethod
    def hexStr2Bytes(str):
        hex_str = str
        byte_arr = bytearray(int(byte, 16) for byte in hex_str.split())
        return byte_arr

    @staticmethod
    def megerBuf(buf1,buf2):
        return buf1+buf2




class ComDriver():
    responseStr="";
    
    OnReceive=None;

    def __init__(self,port,onReceive=None):
        ComDriver.OnReceive=onReceive;
        self.m_rxBuf=[0]*256;
        self.m_rxBufLen=0;
        self.port=port;
        self.serial = serial.Serial("COM"+str(port), 115200, timeout=200,stopbits=2)
        if self.serial.isOpen():
            print("COM"+str(port), "open success")
        else:
            print("open failed")

    def run(self) -> None:
        while True:
            n=self.Receive(self.m_rxBuf,100);
            if n>0:
                ComDriver.OnReceive(self.m_rxBuf[0:n])
            time.sleep(0.5)



    def listen(self):
        t2 = threading.Thread(target=self.run)
        t2.start()


    @staticmethod
    def getComList():
        port_list = serial.tools.list_ports.comports()
        return port_list


    def Close(self):
        self.serial.close()
        print(self.serial.name + "closed.")


    def Receive(self,dstBuf,toRecvSize,offset=0):
        received_data=self.serial.read_all()
        n=min(len(received_data),toRecvSize)
        for i in range(0, n, 1):
            dstBuf[i+offset]=received_data[i]
        return n



    def Send(self,srcBuf,toSendLen=0):
        if toSendLen==0:
            toSendLen=len(srcBuf)
        self.serial.write(srcBuf[0:toSendLen])
        return
    
    def SendStr(self,str,toSendLen=0):
        bs=BinConvert.text2bytes(str)
        self.serial.write(bs)
        return